iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 22
0
Software Development

python 自學系列 第 22

python day22(concurrency、parallelism)

  • 分享至 

  • xImage
  •  

concurrency & parallelism

concurrency 和 parallelism 有很多文章都在介紹這兩個概念,看了很多文章後,我覺得有看到一個最容易懂的例子,concurrency 就是真正運算的 core 只會有一個,由於 core 只會有一個所以當多個 thread 搶一個 core 的資源,速度提升有限有時候甚至可能會變慢.而 parallelism 可以真的運用到多個核心同時計算,但當要遇到 aggregate 的時候,parallelism 由於是在各自的 Process 資源沒有共享,可能需要運用一些額外的方式來 aggregate.在 python 裡 threading 模組像是 concurrency,而 multiprocessing 模組像是 parallelism.

threading

threading 模組可以讓要執行工作變成一個 thread 執行.所以這邊先建立一個 function,用來計時秒數,每次根據輸入的秒數來倒數,直到秒數等於 0.

>>> import time
>>> def count_time(n):
...  while n > 0:
...   print('Time is {} '.format(n))
...   n -= 1
...   time.sleep(1)
...

建立一個 Thread 物件,並把要執行的工作指令給 target,並且可透過 args 帶參數給 target.當執行t.start()執行緒就會開始執行.

>>> from threading import Thread
>>> t = Thread(target=count_time , args=(10,))
>>> t.start()
Time is 10
>>> Time is 9
Time is 8
Time is 7
Time is 6
Time is 5
Time is 4
Time is 3
Time is 2
Time is 1

可以用 is_alive 檢查該執行緒是否還活著.

>>> t.is_alive()
False

在 python 使用 Thread 會被 Global Interpreter Lock(GIL) Lock 住,為了避免一些執行緒的問題.所以使用 thread 不一定會比較快,因為實際上只會有一個 core 在計算,通常 Thread 會比較常用在需要大量 IO 的時候.使用 Thread 只能達到 concurrency,如果要達到 Parallelism 需要使用 multiprocessing 的模組.

multiprocessing

將上面的例子改成使用 multiprocessing 執行.一樣先定義要執行的工作.

>>> def count_time(n,name):
...  while n > 0:
...   print('{} is {} '.format(name,n))
...   n -= 1
...   time.sleep(3)
...

接著 import multiprocessing 模組,然後建立 Process 並且 start 執行.

>>> import multiprocessing as mp
>>> for i in range(5,11,2):
...  p = mp.Process(target=count_time,args=(i,'Task-{}'.format(i)))
...  p.start()
...
>>> Task-5 is 5
Task-7 is 7
Task-9 is 9
Task-5 is 4
Task-7 is 6
Task-9 is 8
Task-5 is 3
Task-7 is 5
Task-9 is 7
Task-5 is 2
Task-7 is 4
Task-9 is 6
Task-5 is 1
Task-7 is 3
Task-9 is 5
Task-7 is 2
Task-9 is 4
Task-7 is 1
Task-9 is 3
Task-9 is 2
Task-9 is 1

測試資源共享

使用全域變數測試 thread 與 multiprocessing 的差異,由於 add_sum function 內的 sum 是全域變數,但在 function 只要有對全域變數做給值的動作(+=) sum 就會變成是區域變數,導致程式執行出錯,所以需加上global sum

>>> def add_sum(n):
...  global sum
...  print(sum , n)
...  sum += n
...  print('sum is {}'.format(sum))

使用 thread 計算全域變數的 sum 答案是 10,表示 thread 之間是共用了 sum 變數而且有使用鎖來避免計算時出現錯誤.

>>> sum = 0
>>> for i in range(1,5):
...  t = Thread(target=add_sum , args=(i,))
...  t.start()
...
0 1
sum is 1
1 2
sum is 3
3 3
sum is 6
6 4
sum is 10
>>> print(sum)
10

使用 multiprocessing 的方式可以看到每個 Process 讀到的 sum 都是初始值 0,表示 Process 之間沒有共用 sum 變數,所以全域變數的 sum 還是 0.

>>> sum = 0
>>> for i in range(1,5):
...  p = mp.Process(target=add_sum , args=(i,))
...  p.start()
...
0 1
sum is 1
>>> 0 2
sum is 2
0 3
sum is 3
0 4
sum is 4

>>> print(sum)
0


上一篇
python day21(xml)
下一篇
python day23(urllib)
系列文
python 自學30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言